package com.liuhuanss.voiceprint.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * HTTP工具类
 * 用于处理讯飞AI API的HTTP请求
 * 
 * @author liuhuanss
 * @version 1.0
 */
@Component
@Slf4j
public class HttpUtil {

    /**
     * 执行POST请求
     * 
     * @param requestUrl 请求URL
     * @param appId 应用ID
     * @param apiSecret API密钥
     * @param apiKey API Key
     * @param params 请求参数
     * @return 响应结果
     * @throws Exception 异常
     */
    public String doPost(String requestUrl, String appId, String apiSecret, String apiKey, String params) throws Exception {
        log.debug("开始执行POST请求，URL: {}", requestUrl);
        
        URL realUrl = new URL(buildRequestUrl(requestUrl, apiSecret, apiKey));
        URLConnection connection = realUrl.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
        
        httpURLConnection.setDoInput(true);
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setRequestMethod("POST");
        // 根据讯飞API要求，使用JSON格式
        httpURLConnection.setRequestProperty("Content-Type", "application/json");
        httpURLConnection.setConnectTimeout(10000); // 10秒连接超时
        httpURLConnection.setReadTimeout(30000); // 30秒读取超时

        // 发送请求参数
        try (OutputStream out = httpURLConnection.getOutputStream()) {
            log.debug("发送请求参数: {}", params);
            out.write(params.getBytes("UTF-8"));
            out.flush();
        }

        // 读取响应
        InputStream is = null;
        try {
            is = httpURLConnection.getInputStream();
            String response = readAllBytes(is);
            log.debug("收到响应: {}", response);
            return response;
        } catch (Exception e) {
            is = httpURLConnection.getErrorStream();
            String errorResponse = readAllBytes(is);
            log.error("请求失败，错误码: {}, 错误信息: {}", httpURLConnection.getResponseCode(), errorResponse);
            throw new Exception("HTTP请求失败: " + httpURLConnection.getResponseMessage() + ", 详细信息: " + errorResponse);
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    /**
     * 构建请求URL
     * 包含鉴权参数
     * 
     * @param requestUrl 原始请求URL
     * @param apiSecret API密钥
     * @param apiKey API Key
     * @return 构建后的URL
     */
    public String buildRequestUrl(String requestUrl, String apiSecret, String apiKey) {
        try {
            // 替换schema前缀，原因是URL库不支持解析包含ws,wss schema的url
            String httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://", "https://");
            URL url = new URL(httpRequestUrl);
            
            // 获取当前日期并格式化
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());

            String host = url.getHost();
            // 只有当端口明确指定且不是默认端口时才添加端口号
            if (url.getPort() != -1 && url.getPort() != 80 && url.getPort() != 443) {
                host = host + ":" + url.getPort();
            }
            
            // 构建签名字符串 - 按照讯飞API文档要求
            // signature_origin格式: host: $host\ndate: $date\n$request-line
            // request-line格式: POST /v1/private/s782b4996 HTTP/1.1
            String requestLine = "POST " + url.getPath() + " HTTP/1.1";
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n")
                    .append("date: ").append(date).append("\n")
                    .append(requestLine);
            
            log.debug("签名原始字符串: {}", builder.toString());
            
            // 生成签名 - 使用HMAC-SHA256算法
            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("hmacsha256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);
            
            log.debug("生成的signature: {}", sha);

            // 构建authorization - 按照讯飞API文档格式
            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", 
                    apiKey, "hmac-sha256", "host date request-line", sha);
            log.debug("authorization原始字符串: {}", authorization);
            
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(charset));
            log.debug("base64编码后的authorization: {}", authBase);
            
            // 构建最终URL
            String finalUrl = String.format("%s?authorization=%s&host=%s&date=%s", 
                    requestUrl, 
                    URLEncoder.encode(authBase, "UTF-8"), 
                    URLEncoder.encode(host, "UTF-8"), 
                    URLEncoder.encode(date, "UTF-8"));
            
            log.debug("构建的请求URL: {}", finalUrl);
            return finalUrl;
            
        } catch (Exception e) {
            log.error("构建请求URL失败", e);
            throw new RuntimeException("构建请求URL失败: " + e.getMessage(), e);
        }
    }

    /**
     * 读取输入流数据
     * 
     * @param is 输入流
     * @return 字符串
     * @throws IOException IO异常
     */
    private String readAllBytes(InputStream is) throws IOException {
        if (is == null) {
            return "";
        }
        
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        return sb.toString();
    }

    /**
     * 读取文件为字节数组
     * 
     * @param filePath 文件路径
     * @return 字节数组
     * @throws IOException IO异常
     */
    public static byte[] readFile(String filePath) throws IOException {
        try (InputStream in = new FileInputStream(filePath)) {
            return inputStreamToByteArray(in);
        }
    }

    /**
     * 将输入流转换为字节数组
     * 
     * @param in 输入流
     * @return 字节数组
     * @throws IOException IO异常
     */
    private static byte[] inputStreamToByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    /**
     * Base64编码字节数组
     * 
     * @param data 字节数组
     * @return Base64编码字符串
     */
    public static String encodeBase64(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }

    /**
     * Base64解码字符串
     * 
     * @param base64Str Base64字符串
     * @return 解码后的字节数组
     */
    public static byte[] decodeBase64(String base64Str) {
        return Base64.getDecoder().decode(base64Str);
    }
}